#include <iostream>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <fcntl.h>
#include <cstring>
#include <cerrno>
#include <cassert>
#include <cstdlib>
#include <time.h>

const int BUFFER_SIZE = 1023;

int setNonBlocking(int fd) {
    int oldOption = fcntl(fd, F_GETFL);
    int newOption = oldOption | O_NONBLOCK;
    fcntl(fd, F_SETFL, newOption);
    return oldOption;
}

int unblockConnect(const char* ip, int port, int time) {
    int ret = 0;
    struct sockaddr_in address;
    address.sin_family = AF_INET;
    inet_pton(AF_INET, ip, &address.sin_addr);
    address.sin_port = htons(port);

    int sockFd = socket(AF_INET, SOCK_STREAM, 0);
    int fdopt = setNonBlocking(sockFd);
    ret = connect(sockFd, (struct sockaddr*)&address, sizeof(address));
    if(ret = 0){
        cout << "connect with server immediately" << endl;
        fcntl(sockFd, F_SETFL, fdopt); // 恢复为阻塞模式
        return sockFd;
    }
    else if (errno != EINPROGRESS) {
        cout << "unblock connect not support: " << strerror(errno) << endl;
        return -1;
    }

    fd_set read_fds;
    fd_set write_fds;
    struct timeval timeout;

    FD_ZERO(&read_fds);
    FD_SET(sockFd, &read_fds);

    timeout.tv_sec = time;
    timeout.tv_usec = 0;

    ret = select(sockFd + 1, nullptr, &write_fds, &read_fds, &timeout);
    if (ret <= 0) {
        cout << "connect time out or error: " << strerror(errno) << endl;
        close(sockFd);
        return -1;
    }
    if (!FD_ISSET(sockFd, &write_fds)) {
        cout << "no events on sockfd found" << endl;
        close(sockFd);
        return -1;
    }

    int error = 0;
    socklen_t len = sizeof(error);
    if(getsockopt(sockFd, SOL_SOCKET, SO_ERROR, &error, &len) < 0) {
        cout << "get socket option failed: " << strerror(errno) << endl;
        close(sockFd);
        return -1;
    }

    // 错误不为0，表示连接失败
    if (error != 0) {
        cout << "connection failed after select with the error: " << strerror(error) << endl;
        close(sockFd);
        return -1;
    }

    cout << "connection ready after select with the socket: " << sockFd << endl;
    fcntl(sockFd, F_SETFL, fdopt); // 恢复为阻塞模式
    return sockFd;
}